﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
using System.Xml.Serialization;

[Serializable]
public class HairData
{
    public HairData() { }
    public HairData(Hair hair)
    {
        name = hair.name;
        genData = hair.genData;
        curveData = hair.curveData;
        curveData.relaHairsName = curveData.relaHairs.Empty() ? null :
            curveData.relaHairs.GetNames();
        renderData = hair.renderData;
    }
    public string name;
    public GenData genData;
    public CurveData curveData;
    public RenderData renderData;
    public EditData editData;
    public HairData Clone()
    {
        var n = new HairData();
        n.name = name;
        n.genData = genData.Clone();
        n.curveData = curveData.Clone();
        n.renderData = renderData.Clone();
        return n;
    }
}
[Serializable]
public class RenderData
{
    public RenderData() { }
    public string matName;
    public RenderData Clone()
    {
        return (RenderData)MemberwiseClone();
    }
}
[Serializable]
public class RenderDataSet
{
    public RenderDataSet() { }
    public List<MatPropIns> props;
    //public List<string> texNames;
    public RenderDataSet Clone()
    {
        var n = (RenderDataSet)MemberwiseClone();
        n.props = props.CloneMw();
        return n;
    }
}
[Serializable]
public class MatPropIns : ICloneable
{
    public MatPropIns() { }
    public Material Set(Material material)
    {
        var mat = Material.Instantiate(material);
        switch (propType)
        {
            case MatPropType.Color:
                mat.SetColor(propName, _color);
                break;
            case MatPropType.Int:
                mat.SetInt(propName, _int);
                break;
            case MatPropType.Float:
                mat.SetFloat(propName, _float);
                break;
            case MatPropType.Vector:
                mat.SetVector(propName, _vector);
                break;
            case MatPropType.Texture:
                mat.SetTexture(propName, _tex);
                break;
            default:
                throw null;
        }
        mat.name = matName;
        return mat;
    }
    public object Clone()
    {
        return MemberwiseClone();
    }

    public MatPropType propType;
    public string propName;
    public string matName;
    [XmlIgnore] public Texture _tex;
    public string _texName;
    public Color _color;
    public int _int;
    public float _float;
    public Vector4 _vector;
}
[Serializable]
public class EditData
{
    public EditData() { }
}
[Serializable]
public class HairDataSet
{
    public HairDataSet() { }
    public List<HairData> hairs;
    public RenderDataSet render;
}

public partial class HairGen
{
    string rootPath { get { return Application.dataPath + "/../"; } }
    public string saveFolder { get { return (rootPath + "SaveFiles/").GetDirOrCreate(); } }
    public string savePath { get { return saveFolder + fileName; } }
    public string fileName = "Hairs.xml";
    public string prefabPath { get { return (rootPath + "Prefabs/").GetDirOrCreate(); } }
    List<HairData> hairDatas;
    public RenderDataSet render;
    public List<Material> mats;
    public List<Texture> texs;

    public bool overrideBonePerLength = true;
    public int boneCountMin = 2;
    public bool legacyDataSet;
    // CallBack性能优化，缓存
    // TODO Button list
    // TODO "LegacyLoad Button"
    List<string> names;
    [InspectorCallBack]
    public void InspectorCallBack()
    {
        //print("InspectorCallBack");
    }
    public void GetFileNamesInPath()
    {
        names = new List<string>();

        var dir = new DirectoryInfo(I.saveFolder);
        var fis = dir.GetFiles("*.xml", SearchOption.TopDirectoryOnly);
        foreach (var fi in fis)
        {
            var clipName = fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length);
            names.Add(clipName);
        }
        names.Sort(StringTool.SortList);
    }
    [ShowButtonRow("保存", "读取")]
    void Call(int i)
    {
        if (i == 0) SaveData();
        else if (i == 1) LoadDatas();
    }
    public void SaveData()
    {
        hairDatas = new List<HairData>();
        foreach (var hair in hairs)
        {
            hairDatas.Add(new HairData(hair));
        }
        var n = new HairDataSet();
        n.hairs = hairDatas;
        n.render = render;
        Serializer.XMLSerialize(n, savePath);
    }
    public void LoadDatas()
    {
        if (legacyDataSet) LoadDataLegacy();
        else LoadDataSet();
    }

    void LoadDataSet()
    {
        var hairDataSet = Serializer.XMLDeSerialize<HairDataSet>(savePath);
        ClearHairs();
        var _list = new List<Hair>();
        List<string> hsn = null;
        Hair rlm = null;
        mats = new List<Material>();
        //texs = new List<Texture>();
        render = hairDataSet.render;
        if (render != null && render.props.NotEmpty())
        {
            foreach (var prop in hairDataSet.render.props)
            {
                prop._tex = texs.GetByName(prop._texName);
                mats.Add(prop.Set(hairMat));
            }
        }
        foreach (var hd in hairDataSet.hairs)
        {
            _list.Add(LoadHairFromData(hd));
            if (hd.curveData.relaHairsName.NotEmpty())
            {
                hsn = hd.curveData.relaHairsName;
                rlm = _list.Last();
            }
        }
        foreach (var h in _list)
        {
            h.UpdateMeshCol();
            var smr = h.GetComponent<SkinnedMeshRenderer>();
            if (h.renderData != null && h.renderData.matName.NotEmpty())
            {
                var mat = mats.GetByName(h.renderData.matName); 
                smr.sharedMaterial = mat;
            }
        }
        if (rlm != null)
        {
            rlm.curveData.relaHairs = I.Find().GetComs<Hair>(hsn);
        }
        I.OnSelectionChanged();
    }
    void LoadDataLegacy()
    {
        hairDatas = Serializer.XMLDeSerialize<List<HairData>>(savePath);
        ClearHairs();
        var _list = new List<Hair>();
        List<string> hsn = null;
        Hair rlm = null;
        foreach (var hd in hairDatas)
        {
            _list.Add(LoadHairFromData(hd));
            if (hd.curveData.relaHairsName.NotEmpty())
            {
                hsn = hd.curveData.relaHairsName;
                rlm = _list.Last();
            }
        }
        foreach (var h in _list)
        {
            h.UpdateMeshCol();
        }
        if (rlm != null)
        {
            rlm.curveData.relaHairs = I.Find().GetComs<Hair>(hsn);
        }
        I.OnSelectionChanged();
    }
}
